#pragma once
#include "MAIMPConnectedPlaylist.h"
#include <string.h>

namespace dotNetInteropPlugin {
	namespace PluginDev {
		using namespace System;
		using namespace System::Runtime::InteropServices;


		//public interface class IPlaylistManager
		//{
		//public:
		//	MAIMPConnectedPlaylist^ CreateFromFile(String^ FileName, Boolean SetActive, Boolean PlayIt);
		//	MAIMPConnectedPlaylist^ CreateEmpty(String^ Name, Boolean SetActive);
		//	Boolean RemoveAt(Int32 ID);
		//	Boolean Remove(MAIMPConnectedPlaylist^ pls);

		//	void SavePlaylistToFile(IMAIMPPlaylist^ pls, String^ FileName);
		//	void LoadItemsToPlaylistFormFile(IMAIMPPlaylist^ pls, String^ FileName);

		//	property Int32 Count
		//	{
		//		Int32 get();
		//	}
		//	property MAIMPConnectedPlaylist^ default[Int32]
		//	{
		//		MAIMPConnectedPlaylist^ get(Int32 ID);
		//	}
		//	property MAIMPConnectedPlaylist^ ActivePlaylist;
		//	property MAIMPConnectedPlaylist^ PlayingPlaylist;

		//	MAIMPConnectedPlaylist^ Connect(MAIMPDisconnectedPlaylist^ pls, Boolean SetActive, Boolean PlayIt,  Boolean UpdateTags);
		//	MAIMPDisconnectedPlaylist^ Disconnect(MAIMPConnectedPlaylist^ pls, Boolean NeedRemove);
		//	void Disconnect(MAIMPDisconnectedPlaylist^ out, MAIMPConnectedPlaylist^ pls, Boolean NeedRemove);

		//	void PlayFile(MAIMPConnectedPlaylist^ Pls, int FileID);
		//	void PlayFile(int PlsID, int FileID);
		//};




		private ref class MAIMPPlaylistManager: public MarshalByRefObject, public IMAIMPPlaylistManager, public System::IDisposable
		{
		private:
			IAIMP2Controller* inAIMPCtrl;
			IAIMP2PlaylistManager2* inPlsMan;
			IAIMP2Player* inAimpPlayer;

			typedef StaticSingleThreadAllocator TConvAlloc;
			typedef FileInfoManUnmanConverter<TConvAlloc> TemporyFInfConverter;
			
			Int32 GetPlaylistIDByNum(Int32 Num)
			{
				int res = 0;
				inPlsMan->AIMP_PLS_ID_By_Index(Num, &res);
				return res;
			}

		public:
			MAIMPPlaylistManager(IAIMP2Controller* Ctrl, IAIMP2PlaylistManager2* PlsM, IAIMP2Player* plr)
			{
				inAIMPCtrl = Ctrl;
				Ctrl->AddRef();
				inPlsMan = PlsM;
				PlsM->AddRef();
				inAimpPlayer = plr;
				plr->AddRef();
			}


			~MAIMPPlaylistManager()
			{
				if (inAimpPlayer != NULL)
				{
					inAimpPlayer->Release();
					inAimpPlayer = NULL;
				}
				if (inPlsMan != NULL)
				{
					inPlsMan->Release();
					inPlsMan = NULL;
				}
				if (inAIMPCtrl != NULL)
				{
					inAIMPCtrl->Release();
					inAIMPCtrl = NULL;
				}
			}


			virtual MAIMPConnectedPlaylist^ CreateFromFile(String^ FileName, Boolean SetActive, Boolean PlayIt)
			{
				pin_ptr<const WCHAR> strDat = PtrToStringChars(FileName);
				int PlsID = inPlsMan->AIMP_PLS_CreateFromFile((PWCHAR)strDat, SetActive, PlayIt);
				if (PlsID != 0)
					return gcnew MAIMPConnectedPlaylistConcrete(PlsID, inAIMPCtrl, inPlsMan, inAimpPlayer);
				return nullptr;
			}
			virtual MAIMPConnectedPlaylist^ CreateEmpty(String^ Name, Boolean SetActive)
			{
				pin_ptr<const WCHAR> strDat = PtrToStringChars(Name);
				int PlsID = inPlsMan->AIMP_PLS_NewEx((PWCHAR)strDat, SetActive);
				if (PlsID != 0)
					return gcnew MAIMPConnectedPlaylistConcrete(PlsID, inAIMPCtrl, inPlsMan, inAimpPlayer);
				return nullptr;
			}
			virtual Boolean RemoveAt(Int32 ID)
			{
				int PlsID = GetPlaylistIDByNum(ID);
				if (PlsID != 0)
					return inAIMPCtrl->AIMP_PLS_Delete(PlsID);
				return false;
			}
			virtual Boolean Remove(MAIMPConnectedPlaylist^ pls)
			{
				if (nullptr != pls)
					return inAIMPCtrl->AIMP_PLS_Delete(pls->PlaylistID);
				return false;
			}

			virtual void SavePlaylistToFile(IMAIMPPlaylist^ pls, String^ FileName)
			{
				MAIMPConnectedPlaylistConcrete^ tst = dynamic_cast<MAIMPConnectedPlaylistConcrete^>(pls);
				if (tst != nullptr)
				{
					tst->SavePlaylist(FileName);
					return;
				}

				DWORD streamIndex = 0;
				{
					pin_ptr<const WCHAR> strData = PtrToStringChars(FileName);
					streamIndex = inPlsMan->AIMP_PM_SaveStream((PWCHAR)strData);
				}

				if (streamIndex != 0)
				{
					AIMP2FileInfo* prSt = NULL;

					for (int i = 0; i < pls->Count; i++)
					{
						prSt = TemporyFInfConverter::GetUnmanagedFromManaged(pls->GetTrackInformation(i));
						inPlsMan->AIMP_PM_WriteItem(streamIndex, prSt);
						TemporyFInfConverter::DisposeStructure(prSt);
					}
					inPlsMan->AIMP_PM_DestroyStream(streamIndex);
				}
			}
			virtual void LoadItemsToPlaylistFormFile(IMAIMPPlaylist^ pls, String^ FileName)
			{
				MAIMPConnectedPlaylistConcrete^ tst = dynamic_cast<MAIMPConnectedPlaylistConcrete^>(pls);
				if (tst != nullptr)
				{
					tst->LoadTracksFromPlaylist(FileName);
					return;
				}

				DWORD streamIndex = 0;
				int PlCount = 0;
				{
					pin_ptr<const WCHAR> strData = PtrToStringChars(FileName);
					streamIndex = inPlsMan->AIMP_PM_ReadStream((PWCHAR)strData, &PlCount);
				}

				if (streamIndex != 0)
				{
					AIMP2FileInfo* prSt = TemporyFInfConverter::GetPreparedStructure();
					System::Collections::Generic::List<IMAIMPFileInfoReadOnly^>^ fifncol = gcnew System::Collections::Generic::List<IMAIMPFileInfoReadOnly^>();

					for (int i = 0; i < PlCount; i++)
					{
						inPlsMan->AIMP_PM_ReadItem(streamIndex, prSt);
						fifncol->Add(TemporyFInfConverter::GetManagedFromUnmanaged(prSt));
					}
					pls->AddRange(dynamic_cast<System::Collections::Generic::IEnumerable<IMAIMPFileInfoReadOnly^>^>(fifncol));
					inPlsMan->AIMP_PM_DestroyStream(streamIndex);
					TemporyFInfConverter::DisposeStructure(prSt);
				}
			}

			property virtual Int32 Count
			{
				Int32 get()
				{
					return inPlsMan->AIMP_PLS_Count();
				}
			}
			property virtual MAIMPConnectedPlaylist^ default[Int32]
			{
				MAIMPConnectedPlaylist^ get(Int32 ID)
				{
					int PlsID = GetPlaylistIDByNum(ID);
					if (PlsID != 0)
						return gcnew MAIMPConnectedPlaylistConcrete(PlsID, inAIMPCtrl, inPlsMan, inAimpPlayer);
					return nullptr;
				}
			}
			property virtual MAIMPConnectedPlaylist^ default[String^]
			{
				MAIMPConnectedPlaylist^ get(String^ Name)
				{
					MAIMPConnectedPlaylist^ res = nullptr;
					const int AllocSize = 2*1024;
					PWCHAR AllocMem = (PWCHAR)TConvAlloc::Allocate(AllocSize);
					AllocMem[AllocSize/2 - 1] = 0;
					pin_ptr<const WCHAR> SrcStrDat = PtrToStringChars(Name);


					int PlsID = 0;
					for (int i = 0; i < Count; i++)
					{
						PlsID = GetPlaylistIDByNum(i);
						if (PlsID != 0)
						{
							if (SUCCEEDED(inPlsMan->AIMP_PLS_GetName(PlsID, AllocMem, AllocSize/2 - 1)))
							{
								if (wcscmp(SrcStrDat, AllocMem) == 0)
								{
									res = gcnew MAIMPConnectedPlaylistConcrete(PlsID, inAIMPCtrl, inPlsMan, inAimpPlayer);
									break;
								}
							}
						}
					}
					TConvAlloc::Dispose((char*)AllocMem);
					return res;
				}
			}

			property virtual MAIMPConnectedPlaylist^ ActivePlaylist
			{
				 MAIMPConnectedPlaylist^ get()
				 {
					 int PlsID = inPlsMan->AIMP_PLS_ID_ActiveGet();
					 if (PlsID != 0)
						 return gcnew MAIMPConnectedPlaylistConcrete(PlsID, inAIMPCtrl, inPlsMan, inAimpPlayer);
					 return nullptr;
				 }
				 void set(MAIMPConnectedPlaylist^ val)
				 {
					 if (val != nullptr)
						inPlsMan->AIMP_PLS_ID_ActiveSet(val->PlaylistID);
				 }
			}
			property virtual MAIMPConnectedPlaylist^ PlayingPlaylist
			{
				MAIMPConnectedPlaylist^ get()
				{
					int PlsID = inPlsMan->AIMP_PLS_ID_PlayingGet();
					if (PlsID != 0)
						return gcnew MAIMPConnectedPlaylistConcrete(PlsID, inAIMPCtrl, inPlsMan, inAimpPlayer);
					return nullptr;
				}
				void set(MAIMPConnectedPlaylist^ val)
				{
					if (val != nullptr)
						PlayFile(val, 0);
				}
			}


			virtual Boolean IsExist(String^ Name)
			{
				Boolean res = false;
				const int AllocSize = 2*1024;
				PWCHAR AllocMem = (PWCHAR)TConvAlloc::Allocate(AllocSize);
				AllocMem[AllocSize/2 - 1] = 0;
				pin_ptr<const WCHAR> SrcStrDat = PtrToStringChars(Name);


				int PlsID = 0;
				for (int i = 0; i < Count; i++)
				{
					PlsID = GetPlaylistIDByNum(i);
					if (PlsID != 0)
					{
						if (SUCCEEDED(inPlsMan->AIMP_PLS_GetName(PlsID, AllocMem, AllocSize/2 - 1)))
						{
							if (wcscmp(SrcStrDat, AllocMem) == 0)
							{
								res = true;
								break;
							}
						}
					}
				}
				TConvAlloc::Dispose((char*)AllocMem);
				return res;
			}


			virtual MAIMPConnectedPlaylist^ Connect(MAIMPDisconnectedPlaylist^ pls, Boolean SetActive, Boolean PlayIt, Boolean UpdateTags)
			{
				EnumerableByIndexedProperty^ EnByInd = gcnew EnumerableByIndexedProperty(pls);
				MAIMPConnectedPlaylist^ res = CreateEmpty(pls->PlaylistName, SetActive);
				res->AddRange(EnByInd);
				if (UpdateTags)
					res->ReloadFullPlaylistInfo();

				if (PlayIt)
					PlayFile(res, 0);

				return res;
			}
			virtual MAIMPDisconnectedPlaylist^ Disconnect(MAIMPConnectedPlaylist^ pls, Boolean NeedRemove)
			{
				MAIMPDisconnectedPlaylist^ res = gcnew MAIMPDisconnectedPlaylist();
				Disconnect(res, pls, NeedRemove);
				return res;
			}
			virtual void Disconnect(MAIMPDisconnectedPlaylist^ outDat, MAIMPConnectedPlaylist^ pls, Boolean NeedRemove)
			{
				outDat->Clear();
				outDat->PlaylistName = pls->PlaylistName;
				for (int i = 0; i < pls->Count; i++)
					outDat->Add(pls->GetTrackInformation(i));

				if (NeedRemove)
					Remove(pls);
			}


			//===========================================

			virtual void PlayFile(MAIMPConnectedPlaylist^ Pls, int FileID)
			{
				if (Pls != nullptr)
					inAimpPlayer->PlayTrack(Pls->PlaylistID, FileID);
			}
			virtual void PlayFile(int PlsID, int FileID)
			{
				int pid = GetPlaylistIDByNum(PlsID);
				if (pid != 0)
					inAimpPlayer->PlayTrack(pid, FileID);
			}
		};


}
}